require 'core/config/aconfiguredbanana'
require 'core/store/apersistentbanana'
require 'core/anexceptionalbanana'
require 'core/avalidatorybanana'
require 'core/aclockworkbanana'
require 'core/amodelbanana'
require 'yaml'
require 'erb'

class AHandOfBananas
  
  # Satisfy our Rack requirements
  def call(env)
    respond_to(Rack::Request.new(env)).finish
  end

  # this is nobody's business but our own
  private

  def respond_to request
    begin
      config = AConfiguredBanana.new YAML.load(File.open(File.dirname(__FILE__) + "/config/config.yml"))
      store = APersistentBanana.new config
      model = AModelBanana.new store
      request.env['REQUEST_ARRAY'] = parse request
      begin
        model.load request.env['REQUEST_ARRAY']
      rescue AModelBananaException => exc
        if request.env['REQUEST_ARRAY'].count > 1
          begin
            model.load [request.env['REQUEST_ARRAY'][0]]
          rescue AModelBananaException => exc
            # TODO: implement 404 handler if controller can't be found
            return complete_and_utter_failure exc
          end
        else
          return complete_and_utter_failure exc
        end
      end
      require "core/controllers#{model.source}"
      # TODO: ensure this is acceptable and raise an exception otherwise
      fix_length Kernel.const_get(model.controller).respond_to(model, request, config, store)
    rescue Exception => exc
      complete_and_utter_failure exc
    ensure
      # always close shop before leaving    
      store.close
    end
  end
  
  def parse request
    # strip querystring from request and split by /
    if request.env.has_key? 'REDIRECT_QUERY_STRING'
      query = request.env['REDIRECT_QUERY_STRING'].length > 0 ? '?' + request.env['REDIRECT_QUERY_STRING'] : ''
    else 
      query = request.env['QUERY_STRING'].length > 0 ? '?' + request.env['QUERY_STRING'] : ''
    end
    req = request.env['REQUEST_URI'].gsub(query, '').split('/');
    
    # req.count of 0 means home page request
    if req.count == 0
      req = ['/index']
      #return '/index', req
    else
      req.shift
      req[0] = '/' + req[0]
    end
    return req
  end
  
  def complete_and_utter_failure exc
    # TODO: implement absolute failure page
    # eventually this will have a backup absolute failure page (and will log the error)
    # for now, send the error back
    response = Rack::Response.new
    response.write("<pre>\n")
    response.write(exc.class.to_s + ": " + exc.message + "\n")
    response.write(exc.backtrace.join("\n"))
    response.write("</pre>")
    return fix_length response
  end
  
  # Riddle me this - for some reason newlines aren't being counted correctly.
  # TODO: find out WTF and fix it better than this
  def fix_length response
    size = 0
    response.body.each {|str| size += str.scan(/\n/).size}
    size += response.headers['Content-Length'].to_i
    response.headers['Content-Length'] = size.to_s
    return response
  end
end
